// from https://github.com/tc39/proposal-native-promise-adoption
/* eslint-disable jsdoc/no-restricted-syntax */
// eslint-disable-next-line n/no-unsupported-features/es-syntax
const makePromiseKit = Promise.withResolvers.bind(Promise);

/**
 * @template T
 * @typedef {(resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => Promise<void>} Executor
 */

/**
 * @template T
 * @param {Executor<T>} executor
 * @returns {Promise<T>}
 */
async function makePromise(executor) {
  const { promise, resolve } = makePromiseKit();

  executor(
    /**
     * @param {*} value
     * @returns {void}
     */
    (value) => void resolve({ __proto__: null, status: "resolved", value }),
    /**
     * @param {*} reason
     * @returns {void}
     */
    (reason) => void resolve({ __proto__: null, status: "rejected", reason }),
  );

  const resolution = await promise;

  if (resolution.status === "resolved") {
    return await resolution.value;
  }
  throw resolution.reason;
}

/**
 * @class
 * @param {any} executor
 * @returns {Promise<any>}
 */
function SafePromise(executor) {
  // eslint-disable-next-line unicorn/error-message
  if (new.target !== SafePromise) throw new TypeError();

  return makePromise(executor);
}
Object.setPrototypeOf(SafePromise, Promise);
Object.defineProperty(SafePromise, "prototype", {
  value: Promise.prototype,
  writable: false,
});
